package com.dangdang.spel.adviser;

import java.lang.reflect.Method;

import javax.annotation.Resource;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.context.ApplicationContext;
import org.springframework.context.expression.BeanFactoryResolver;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;

import com.dangdang.spel.anno.MyAuth;
import com.dangdang.spel.exception.BusinessException;

@Component
@Aspect
public class MyAuthAspect {
	private ExpressionParser parser = new SpelExpressionParser();
	private LocalVariableTableParameterNameDiscoverer discoverer = new LocalVariableTableParameterNameDiscoverer();

	@Resource
	private ApplicationContext applicationContext;

	@Pointcut("@annotation(com.dangdang.spel.anno.MyAuth)")
	public void pointcut() {
	}

	@Around(value = "pointcut()")
	public Object arround(ProceedingJoinPoint point) throws Throwable {
		Signature signature = point.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;

        Method method = methodSignature.getMethod();
        MyAuth authorize = method.getAnnotation(MyAuth.class);
        String spel = authorize.spel();
        Object[] arguments = point.getArgs();
        boolean result=parseSpel(method,arguments,spel,Boolean.class,Boolean.FALSE);
        if (result) {
            return point.proceed();
        } else {
            throw new BusinessException("没有权限进行该操作");
        }

    }

    /**
     * 解析 spel 表达式
     * @param method          方法
     * @param arguments      参数
     * @param spel          表达式
     * @param clazz         返回结果的类型
     * @param defaultResult 默认结果
     * @return 执行spel表达式后的结果
     */

    private <T> T parseSpel(Method method, Object[] arguments, String spel, Class<T> clazz, T defaultResult) {
        StandardEvaluationContext context = new StandardEvaluationContext();
        context.setBeanResolver(new BeanFactoryResolver(applicationContext));
        String[] params = discoverer.getParameterNames(method);
        for (int len = 0; len < params.length; len++) {
            context.setVariable(params[len], arguments[len]);
        }
        try {
            Expression expression = parser.parseExpression(spel);
            return expression.getValue(context, clazz);
        } catch (Exception e) {
            return defaultResult;
        }
    }
}
